package com.arpa.wms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.StrBuilder;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.arpa.core.web.Result;
import com.arpa.ntocc.common.common.cache.PartyCache;
import com.arpa.ntocc.common.common.exception.ServiceException;
import com.arpa.ntocc.common.common.util.CommonUtil;
import com.arpa.ntocc.common.common.util.UserUtil;
import com.arpa.wms.cache.WarehouseCache;
import com.arpa.wms.cache.WarehouseSpaceCache;
import com.arpa.wms.domain.dto.InventoryDTO;
import com.arpa.wms.domain.dto.WarehouseSpaceDTO;
import com.arpa.wms.domain.entity.*;
import com.arpa.wms.domain.enums.DeleteFlagEnum;
import com.arpa.wms.domain.enums.StatusEnum;
import com.arpa.wms.domain.enums.TempLocationTypeEnum;
import com.arpa.wms.domain.vo.WarehouseSpaceVO;
import com.arpa.wms.mapper.WarehouseSpaceMapper;
import com.arpa.wms.service.IInventoryService;
import com.arpa.wms.service.ILocationService;
import com.arpa.wms.service.IWarehouseSpaceService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 库区 服务实现类
 * </p>
 *
 * @author LEO
 * @since 2020-08-03
 */
@Service
public class WarehouseSpaceServiceImpl extends ServiceImpl<WarehouseSpaceMapper, WarehouseSpace> implements IWarehouseSpaceService {

    private final IInventoryService iInventoryService;
    private final ILocationService iLocationService;
    private final WarehouseSpaceCache warehouseSpaceCache;
    private final WarehouseCache warehouseCache;
    private final PartyCache partyCache;


    public WarehouseSpaceServiceImpl(WarehouseSpaceCache warehouseSpaceCache,
                                     ILocationService iLocationService,
                                     IInventoryService iInventoryService,
                                     WarehouseCache warehouseCache,
                                     PartyCache partyCache) {
        this.warehouseSpaceCache = warehouseSpaceCache;
        this.iLocationService = iLocationService;
        this.iInventoryService = iInventoryService;
        this.warehouseCache = warehouseCache;
        this.partyCache = partyCache;
    }


    /**
     * 保存
     * @param entity
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public boolean save(WarehouseSpace entity) {
        if (StringUtils.isBlank(entity.getCode())) {
            entity.setCode(IdUtil.simpleUUID());
        }
        if (StringUtils.isBlank(entity.getCreatedBy())) {
            entity.setCreatedBy(UserUtil.getCode());
            entity.setCreatedName(partyCache.translate(UserUtil.getCode()));
        }
        entity.setModifiedBy(UserUtil.getCode());
        entity.setModifiedName(partyCache.translate(UserUtil.getCode()));
        entity.setGroupCode(UserUtil.getBranchCode());
        warehouseSpaceCache.flushCache(entity.getCode());
        return super.save(entity);
    }

    /**
     * 根据code更新实体
     * @param entity
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public int updateByCode(WarehouseSpace entity) {
        if (StringUtils.isBlank(entity.getModifiedBy())) {
            entity.setModifiedBy(UserUtil.getCode());
            entity.setModifiedName(partyCache.translate(UserUtil.getCode()));
        }
        warehouseSpaceCache.flushCache(entity.getCode());
        return baseMapper.update(entity,new QueryWrapper<WarehouseSpace>().lambda().eq(WarehouseSpace::getCode,entity.getCode()).eq(WarehouseSpace::getGroupCode,entity.getGroupCode()));
    }

    /**
     * 通过code获取库区信息
     *
     * @param code
     * @return
     */
    @Override
    public WarehouseSpace getByCode(String code) {
        Map<String, Object> temp = this.warehouseSpaceCache.get(code);
        if (MapUtil.isNotEmpty(temp)) {
            return BeanUtil.mapToBean(temp, WarehouseSpace.class, false);
        }
        return null;
    }


    /**
     * 通过code获取库区详细信息
     *
     * @param code
     * @return
     */
    @Override
    public WarehouseSpaceVO getWarehouseSpace(String code) {
        Map<String, Object> temp = this.warehouseSpaceCache.get(code);
        WarehouseSpaceVO warehouseSpace = null;
        if (MapUtil.isNotEmpty(temp)) {
            warehouseSpace = BeanUtil.mapToBean(temp, WarehouseSpaceVO.class, false);
            if (StrUtil.isNotBlank(warehouseSpace.getWarehouseCode())) {
                warehouseSpace.setWarehouseName(warehouseCache.translate(warehouseSpace.getWarehouseCode()));
            }
        }
        return warehouseSpace;
    }

    /**
     * 查询列表
     * @param warehouseSpaceDTO
     * @return
     */
    @Override
    public List<WarehouseSpaceVO> queryList(WarehouseSpaceDTO warehouseSpaceDTO) {
        Warehouse warehouse=new Warehouse();
        //排序字段名需要驼峰转数据库下划线类型字段名
        if (StringUtils.isNotEmpty(warehouseSpaceDTO.getSortField())) {
            warehouseSpaceDTO.setSortField(CommonUtil.camel2Underline(warehouseSpaceDTO.getSortField()));
        }
        List<WarehouseSpaceVO> warehouseSpaceVOList = baseMapper.queryList(warehouseSpaceDTO);
        return warehouseSpaceVOList;
    }

    /**
     * 查询合计,包含总数
     * @param warehouseSpaceDTO
     * @return
     */
    @Override
    public WarehouseSpaceVO queryListSum(WarehouseSpaceDTO warehouseSpaceDTO) {
        WarehouseSpaceVO warehouseSpaceVO = baseMapper.queryListSum(warehouseSpaceDTO);
        return warehouseSpaceVO;
    }

    /**
     * 删除库区
     *
     * @param codes
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result deleteByCode(List<String> codes) {

        Map<String, Object> result = this.batchdel(codes);
        Integer success = MapUtil.getInt(result, "success");
        List<String> notDelete = MapUtil.get(result, "notDelete", List.class);
        List<String> InInventory = MapUtil.get(result, "inInventory", List.class);
        int failNum = codes.size() - success;
        StringBuilder info = new StringBuilder();
        info.append("删除成功" + success + "条；失败" + failNum + "条；");
        if (IterUtil.isNotEmpty(notDelete)) {
            for (String m : notDelete) {
                info.append("<br><font color='red'>库区【" + m + "】删除失败，已被启用过;</font>");
            }
        }
        if (IterUtil.isNotEmpty(InInventory)) {
            for (String m : InInventory) {
                info.append("<br><font color='red'>库区【" + m + "】删除失败，已被占用;</font>");
            }
        }
        return Result.ok(info.toString());

    }

    /**
     *  根据库区code更新启用、停用状态
     * @param codes
     * @return
     */
    @Override
    public int activeStatus(List<String> codes) {
        int num = this.changeStatus(codes, StatusEnum.ACTIVE, DeleteFlagEnum.NOTDELETE.getCode().toString());
        return num;

    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public int activeStatusByWarehouseCodes(List<String> warehouseCodes) {

        iLocationService.changeStatusByWarehouseCodes(warehouseCodes, StatusEnum.ACTIVE.getValue(), DeleteFlagEnum.NOTDELETE.getCode().toString());

        return baseMapper.changeStatusByWarehouseCodes(warehouseCodes, StatusEnum.ACTIVE.getValue(), DeleteFlagEnum.NOTDELETE.getCode().toString(),UserUtil.getBranchCode());
    }


    /**
     *  根据库区code更新启用、停用状态
     * @param codes
     * @return
     */
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Map<String, Object> unactiveStatus(List<String> codes) {
        Map<String, Object> result;
        result = new HashMap<>();
        int num = 0;
        String codesStr = codes.stream().map(c -> StrUtil.wrap(c, "'")).collect(Collectors.joining(","));
        //获取0库存的库区code
        List<String> emptyWarehouseSpaceCodes = this.baseMapper.emptyWarehouseSpace(codesStr,UserUtil.getBranchCode());
        if (IterUtil.isNotEmpty(emptyWarehouseSpaceCodes)) {
            num = this.changeStatus(emptyWarehouseSpaceCodes, StatusEnum.UNACTIVE, "");
            iLocationService.update(new UpdateWrapper<Location>().lambda().in(Location::getSpaceCode, emptyWarehouseSpaceCodes).eq(Location::getGroupCode,UserUtil.getBranchCode())
                    .set(Location::getStatus, StatusEnum.UNACTIVE));
        }
        //库存不为0的库区
        List<String> useCodes = codes.stream().filter(code -> !emptyWarehouseSpaceCodes.contains(code)).collect(Collectors.toList());
        List<String> spaceNames = useCodes.stream().map(info -> {
            return warehouseSpaceCache.translate(info);
        }).collect(Collectors.toList());
        result.put("spaceNames", spaceNames);
        result.put("success", num);
        return result;

    }

    /**
     * 校验库区信息
     * @param entity
     * @return
     */
    @Override
    public Result validateSpace(WarehouseSpace entity) {
        // 校验必填项
        if (StrUtil.isBlank(entity.getWarehouseCode())) {
            return Result.error("所属仓库不能为空");
        }
        if (StrUtil.isBlank(entity.getSerialNumber())) {
            return Result.error("库区编码不能为空");
        }

        if (StrUtil.isBlank(entity.getName())) {
            return Result.error("库区名称不能为空");
        }
        if (StrUtil.isBlank(entity.getTemperature())) {
            return Result.error("温层不能为空");
        }
        // 校验库区编码是否唯一, 同仓库下不能有相同的库区编码
        List<WarehouseSpace> warehouseSpaces = this.list(new LambdaQueryWrapper<WarehouseSpace>()
                .eq(WarehouseSpace::getWarehouseCode, entity.getWarehouseCode())
                .eq(WarehouseSpace::getSerialNumber, entity.getSerialNumber())
                .eq(WarehouseSpace::getGroupCode, UserUtil.getBranchCode()));
        // 将自身过滤掉
        warehouseSpaces = warehouseSpaces.stream().filter(e -> !e.getCode().equals(entity.getCode())).collect(Collectors.toList());
        if (!warehouseSpaces.isEmpty()) {
            return Result.error("存在相同的库区编码，请确认后重新操作。");
        }

        return Result.ok();
    }


    /**
     * 变更库区状态
     *
     * @param codes  标识
     * @param active 状态
     * @return
     */
    private int changeStatus(List<String> codes, StatusEnum active, String deleteFlag) {
        int num = 0;
        boolean flag = false;
        if(IterUtil.isNotEmpty(codes)){
            for(String code: codes){
                if(active.getValue().equals(StatusEnum.ACTIVE.getValue())){
                    flag = this.update(new UpdateWrapper<WarehouseSpace>().lambda().set(WarehouseSpace::getStatus, active).set(WarehouseSpace::getDeleteFlag, DeleteFlagEnum.NOTDELETE.getCode())
                            .eq(WarehouseSpace::getCode, code).eq(WarehouseSpace::getGroupCode,UserUtil.getBranchCode()));
                }else {
                    flag = this.update(new UpdateWrapper<WarehouseSpace>().lambda().set(WarehouseSpace::getStatus, active)
                            .eq(WarehouseSpace::getCode, code).eq(WarehouseSpace::getGroupCode,UserUtil.getBranchCode()));
                }
                if(flag){
                    num++;
                }
            }
        }
        return num;
    }

    /**
     * 前台页面库区下拉数据
     * 查询当前登录用户所属机构下启用的仓库库区，同时过滤掉临时库区
     * @param warehouseCode
     * @return
     */
    @Override
    public List<WarehouseSpaceVO> findWarehouseSpace(String warehouseCode) {
        Map<String,Object> map;
        map = new HashMap<>();
        map.put("warehouseCode",warehouseCode);
        map.put("groupCode",UserUtil.getBranchCode());
        map.put("status","0");
        map.put("tempSpace",0);
        if (StrUtil.isEmpty(warehouseCode)) {
            map.put("warehouseCodes", UserUtil.getAuthorizeWarehouseCodes());
        }
        return baseMapper.findAllByWarehouseCode(map);
    }

    /**
     * 前台页面库区下拉数据， 包含临时库区
     * 查询当前登录用户所属机构下启用的仓库库区，同时过滤掉临时库区
     *
     * @param warehouseCode
     * @return
     */
    @Override
    public List<WarehouseSpaceVO> findAllWarehouseSpace(String warehouseCode) {
        Map<String,Object> map;
        map = new HashMap<>();
        map.put("warehouseCode",warehouseCode);
        map.put("groupCode",UserUtil.getBranchCode());
        map.put("status","0");
        if (StrUtil.isEmpty(warehouseCode)) {
            map.put("warehouseCodes", UserUtil.getAuthorizeWarehouseCodes());
        }
        return baseMapper.findAllByWarehouseCode(map);
    }

    /**
     * 创建临时库区
     * @param warehouseCode
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public WarehouseSpace createTempSpace(String warehouseCode) {
        WarehouseSpace space = new WarehouseSpace();
        space.setCode(IdUtil.simpleUUID());
        space.setGroupCode(UserUtil.getBranchCode());
        space.setName("临时库区");
        space.setSerialNumber(TempLocationTypeEnum.LSKQ.getValue());
        space.setWarehouseCode(warehouseCode);
        space.setStatus(StatusEnum.ACTIVE.getValue());
        space.setTempSpace(1);
        space.setDeleted(0);
        space.setGroupCode(UserUtil.getBranchCode());
        this.save(space);
        return space;
    }

    /**
     * 批量删除
     * @param codes
     */
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Map<String, Object> batchdel(List<String> codes) {
        HashMap<String, Object> result;
        result = new HashMap<>();
        List<WarehouseSpaceVO> warehouses = queryByCodes(codes);
        Map<String, String> warehouseMap = warehouses.stream().collect(Collectors.toMap(WarehouseSpaceVO::getCode, WarehouseSpaceVO::getName));
        //不可删除code
        List<String> notDeleteCodes = warehouses.stream().filter(info -> info.getDeleteFlag().intValue() == DeleteFlagEnum.NOTDELETE.getCode().intValue())
                .map(WarehouseSpaceVO::getCode).collect(Collectors.toList());
        List<String> notDeleteName = notDeleteCodes.stream().map(warehouseMap::get).collect(Collectors.toList());
        result.put("notDelete", notDeleteName);
        List<String> tempCode = codes.stream().filter(code -> !notDeleteCodes.contains(code)).collect(Collectors.toList());
        List<String> tempNoDeleteCode = new ArrayList<>();
        List<String> inventorynotDeleteName = new ArrayList<>();
        tempCode.stream().forEach(code -> {
            InventoryDTO inventoryDTO = new InventoryDTO();
            inventoryDTO.setWarehouseCode(code);
            inventoryDTO.setGroupCode(UserUtil.getBranchCode());
            BigDecimal quantity = iInventoryService.queryInventorySum(inventoryDTO);
            if (quantity.compareTo(BigDecimal.ZERO) != 0) {
                tempNoDeleteCode.add(code);
                inventorynotDeleteName.add(warehouseMap.get(code));
            }
        });
        result.put("inInventory", inventorynotDeleteName);
        int num = 0;
        if (IterUtil.isNotEmpty(tempCode)) {
            List<String> deleteCodes = tempCode.stream().filter(code -> !tempNoDeleteCode.contains(code)).collect(Collectors.toList());
            if (IterUtil.isNotEmpty(deleteCodes)) {
                num = delete(deleteCodes);
            }
        }
        result.put("success",num);
        return result;
    }


    private int delete(List<String> list) {
        int num = 0;
        if (IterUtil.isNotEmpty(list)) {
            for (String code : list) {
                boolean flag = this.update(new UpdateWrapper<WarehouseSpace>().lambda().eq(WarehouseSpace::getCode, code).eq(WarehouseSpace::getGroupCode,UserUtil.getBranchCode())
                        .set(WarehouseSpace::getDeleted, 1));
                if (flag) {
                    num++;
                    this.warehouseSpaceCache.flushCache(code);
                    // 同步删除该库区下的库位
                    iLocationService.remove(new UpdateWrapper<Location>().lambda().eq(Location::getSpaceCode, code));
                    /*
                     TODO 清除库位缓存
                    this.locationCache.flushCache();
                    */
                }
            }
        }
        return num;
    }

    @Override
    public List<WarehouseSpaceVO> queryByCodes(List<String> codes) {

        return baseMapper.getByCodes(codes,UserUtil.getBranchCode());
    }
}
